home *** CD-ROM | disk | FTP | other *** search
-
- /*© Copyright 1992 UserLand Software, Inc. All Rights Reserved.*/
-
-
- /*
- Version 2.0:
-
- 1/22/92 DW: provide for dialog on receipt of a 'done' message
-
- 1. Frontier sets the 'errs' parameter if a shared script ended in an
- error. we set up the IAC globals so that the scriptcomplete handler
- can get the error string and display it in a dialog.
-
- 6/29/92 DW: fast menu sharing if Frontier 2.0 is present.
-
- 1. this is possible because Frontier 2.0 installs system event handlers
- for the most time-consuming of the menu sharing operations.
-
- 8/13/92 DW: cleaner way of killing scripts.
-
- 1. In CancelSharedScript, we now send a message to the menu sharing server
- asking that the script be killed. But only if we're talking to a server that
- supports fast messages.
- */
-
-
- #include <processes.h>
- #include <Menus.h>
- #include <GestaltEqu.h>
- #include <iac.h>
- #include "menusharing.h"
-
-
-
- tyMSglobals MSglobals; /*Menu Sharing globals, all in one struct*/
-
-
-
- static Boolean ServerSupportsFastMessages (void) {
-
- /*
- return true if there's a system event handler registered to support the
- get-menu-array message. Frontier 2.0 installs such a handler, other servers
- (e.g. Frontier 1.0) don't.
- */
-
- return (IAChandlerinstalled (MSglobals.serverid, 'gmry', true));
- } /*ServerSupportsFastMessages*/
-
-
- static Boolean MSnewverb (OSType verbtoken, AppleEvent *event) {
-
- Boolean fl;
-
- if (ServerSupportsFastMessages ())
- fl = IACnewsystemverb (MSglobals.serverid, verbtoken, event);
- else
- fl = IACnewverb (MSglobals.serverid, MSglobals.serverid, verbtoken, event);
-
- return (fl);
- } /*MSnewverb*/
-
-
- static pascal Boolean ProcessInForeground () {
-
- /*
- return true if we're running in the foreground, false if we're in the
- background.
- */
-
- ProcessSerialNumber currentprocess, frontprocess;
- Boolean fl;
-
- GetCurrentProcess (¤tprocess);
-
- GetFrontProcess (&frontprocess);
-
- SameProcess (¤tprocess, &frontprocess, &fl);
-
- return (fl);
- } /*ProcessInForeground*/
-
-
- static Boolean ServerIsRunning (void) {
-
- /*
- return true if the server application is running.
- */
-
- ProcessInfoRec info;
- ProcessSerialNumber psn;
- Str255 bsname;
- FSSpec fss;
-
- info.processInfoLength = sizeof (info);
-
- info.processName = bsname; /*place to store process name*/
-
- info.processAppSpec = &fss; /*place to store process filespec*/
-
- psn.highLongOfPSN = kNoProcess;
-
- psn.lowLongOfPSN = kNoProcess;
-
- while (GetNextProcess (&psn) == noErr) {
-
- info.processInfoLength = sizeof (ProcessInfoRec);
-
- if (GetProcessInformation (&psn, &info) != noErr)
- continue; /*keep going -- ignore error*/
-
- if (info.processSignature == MSglobals.serverid)
- return (true);
- } /*while*/
-
- return (false); /*loop completed, no server*/
- } /*ServerIsRunning*/
-
-
- static short CountMenuArray (void) {
-
- /*
- return the number of menus in the menu array.
- */
-
- register hdlmenuarray hm = MSglobals.hsharedmenus;
-
- if (hm == nil)
- return (0);
-
- return ((short) (GetHandleSize ((Handle) hm) / sizeof (tysharedmenurecord)));
- } /*CountMenuArray*/
-
-
- static pascal Boolean InstallSharedMenus (short idmenuafter) {
-
- /*
- insert all of the menus in the menuarray into the menu bar. main
- menus are inserted in front of idmenuafter. if idmenuafter is zero,
- main (non-hierarchic) menus will be added to the right of all others.
- */
-
- register hdlmenuarray hm = MSglobals.hsharedmenus;
- register short i, ct;
- tysharedmenurecord item;
-
- ct = CountMenuArray ();
-
- for (i = 0; i < ct; i++) {
-
- item = (**hm) [i];
-
- if (item.flhierarchic)
- InsertMenu (item.hmenu, -1);
- else
- InsertMenu (item.hmenu, idmenuafter);
-
- (**hm) [i].flinserted = true; /*so we'll know it needs to be removed*/
- } /*for*/
-
- return (true);
- } /*InstallSharedMenus*/
-
-
- static short GetMenuHandles (void) {
-
- /*
- loop through the menuarray, send an IAC message to the menu server requesting
- that each MenuHandle be sent to us.
- */
-
- register hdlmenuarray hm = MSglobals.hsharedmenus;
- register short i, ct;
- AppleEvent event, reply;
- register short fl;
- MenuHandle hmenu;
- OSType binarytype;
-
- ct = CountMenuArray ();
-
- for (i = 0; i < ct; i++) {
-
- if (!MSnewverb ('gmhd', &event))
- return (false);
-
- IACglobals.event = &event;
-
- if (!IACpushlongparam (MSglobals.clientid, 'menp'))
- return (false);
-
- if (!IACpushshortparam (i, 'idix'))
- return (false);
-
- if (!IACsendverb (IACglobals.event, &reply))
- return (false);
-
- IACglobals.reply = &reply;
-
- IACglobals.event = &reply;
-
- fl = IACgetbinaryparam (keyDirectObject, (Handle *) &hmenu, &binarytype);
-
- IACdisposeverb (&reply);
-
- if (!fl)
- return (false);
-
- (**hm) [i].hmenu = hmenu;
- } /*for*/
-
- return (true);
- } /*GetMenuHandles*/
-
-
- static pascal Boolean GetSharedMenus (short firstresource) {
-
- /*
- call the menu server to get a menuarray, keyed off of our application id.
-
- firstresource is the starting id to be used for the menus; if there are
- n menus, their ids will range from firstresource to firstresource + n - 1.
- */
-
- AppleEvent event, reply;
- register short fl;
- OSType binarytype;
-
- if (!MSnewverb ('gmry', &event))
- return (false);
-
- IACglobals.event = &event;
-
- if (!IACpushlongparam (MSglobals.clientid, 'menp'))
- return (false);
-
- if (!IACpushshortparam (firstresource, 'res1'))
- return (false);
-
- if (!IACsendverb (&event, &reply))
- return (false);
-
- IACglobals.event = &reply;
-
- fl = IACgetbinaryparam (keyDirectObject, (Handle *) &MSglobals.hsharedmenus, &binarytype);
-
- IACdisposeverb (&reply);
-
- if (!fl)
- return (false);
-
- return (GetMenuHandles ());
- } /*GetSharedMenus*/
-
-
- pascal Boolean DisposeSharedMenus (void) {
-
- /*
- completely dispose of the menuarray and the menu handles it contains.
-
- 10/10/91 DW: check for no shared menus before disposing, save code if
- its ever called from more than one place. also set the global handle to
- nil after disposing and redraw the menu bar.
- */
-
- register hdlmenuarray hm = MSglobals.hsharedmenus;
- register short i;
- register short ctmenus;
- tysharedmenurecord item;
-
- if (hm == nil) /*no shared menus to toss*/
- return (true);
-
- ctmenus = CountMenuArray ();
-
- for (i = 0; i < ctmenus; i++) {
-
- item = (**hm) [i];
-
- if (item.flinserted)
- DeleteMenu (item.idmenu);
-
- DisposeMenu (item.hmenu);
- } /*for*/
-
- DisposHandle ((Handle) hm);
-
- MSglobals.hsharedmenus = nil;
-
- DrawMenuBar ();
-
- return (true);
- } /*DisposeSharedMenus*/
-
-
- pascal Boolean IsSharedMenu (short idmenu) {
-
- /*
- return true if the indicated menu is one of the shared menus.
- */
-
- register hdlmenuarray hm = MSglobals.hsharedmenus;
- register short ct, i;
- tysharedmenurecord item;
-
- ct = CountMenuArray ();
-
- for (i = 0; i < ct; i++) {
-
- item = (**hm) [i];
-
- if (item.idmenu == idmenu)
- return (true);
- } /*for*/
-
- return (false);
- } /*IsSharedMenu*/
-
-
- pascal Boolean EnableSharedMenus (Boolean flenable) {
-
- /*
- Enables or disables the the menus in the specified menu array.
-
- Always returns true.
- */
-
- register hdlmenuarray hm = MSglobals.hsharedmenus;
- register short i;
- register short ctmenus;
- register MenuHandle hmenu;
-
- ctmenus = CountMenuArray ();
-
- for (i = 0; i < ctmenus; i++) {
-
- hmenu = (**hm) [i].hmenu;
-
- if (flenable)
- EnableItem (hmenu, 0);
- else
- DisableItem (hmenu, 0);
- } /*for*/
-
- DrawMenuBar ();
-
- return (true);
- } /*EnableSharedMenus*/
-
-
- pascal Boolean RunSharedMenuItem (short idmenu, short iditem) {
-
- /*
- call the menu server to run the script linked to the indicated menu item.
-
- the script will execute asynchonously, after this call returns.
-
- SDK 2.0: if the server isn't running, remove the shared menus and return
- false. this will only happen if the server has crashed without letting us
- know that our menus are dirty.
- */
-
- AppleEvent event, reply;
- Boolean fl;
-
- if (!ServerIsRunning ()) {
-
- MSglobals.fldirtysharedmenus = true;
-
- return (false);
- }
-
- if (!IACnewverb (MSglobals.serverid, MSglobals.serverid, 'runm', &event))
- return (false);
-
- IACglobals.event = &event;
-
- if (!IACpushlongparam (MSglobals.clientid, 'menp'))
- return (false);
-
- if (!IACpushshortparam (idmenu, 'mid '))
- return (false);
-
- if (!IACpushshortparam (iditem, 'mitm'))
- return (false);
-
- if (!IACsendverb (&event, &reply))
- return (false);
-
- IACglobals.event = &reply;
-
- fl = IACgetlongparam (keyDirectObject, &MSglobals.idscript);
-
- IACdisposeverb (&reply);
-
- return (fl && (MSglobals.idscript != 0));
- } /*RunSharedMenuItem*/
-
-
- pascal Boolean CheckSharedMenus (idinsertafter) short idinsertafter; {
-
- /*
- call this from your main event loop after receiving and processing every
- event. if the menus need updating, we send a message to the server asking
- for our shared menus.
-
- if we load menus, they are assigned resource ids starting with idinsertafter.
- this number must be less than 255 to allow for hierarchic menus, and must be
- small enough so that no menu has an id of greater than 255.
-
- 9/28/91 DW: only update menus if we're the front process. this catches the
- delay on re-loading a changed menu structure on the Multifinder switch. No
- extra burden on the script writer editing the menu bar.
- */
-
- if (!ProcessInForeground ()) /*only update menus if we're the front process*/
- return (true);
-
- if (!MSglobals.fldirtysharedmenus) /*no need for an update, return quickly*/
- return (true);
-
- DisposeSharedMenus ();
-
- if (ServerIsRunning ()) {
-
- if (GetSharedMenus (idinsertafter)) {
-
- InstallSharedMenus (0); /*install to the right of all other menus*/
-
- DrawMenuBar ();
- }
-
- MSglobals.fldirtysharedmenus = false;
- }
-
- else { /*server not running, menus have been updated (ie there are no shared menus)*/
-
- MSglobals.fldirtysharedmenus = false;
- }
-
- return (true);
- } /*CheckSharedMenus*/
-
-
- pascal Boolean SharedScriptRunning () {
-
- /*
- returns true if a shared script is currently running, false otherwise.
-
- it's provided so that an application can intelligently handle cmd-period
- script termination in its keystroke handling routine.
- */
-
- return (MSglobals.flscriptrunning);
- } /*SharedScriptRunning*/
-
-
- pascal Boolean CancelSharedScript () {
-
- /*
- call this when the user presses cmd-period or otherwise indicates to you that
- he or she wants the currently running script to be halted.
-
- 8/13/92 DW: if we're talking to post-2.0 Frontier or Runtime 1.0, we send a
- message to the server telling it to kill the script. otherwise we do it the
- old less elegant way, by setting a flag that gets monitored in calls to
- SharedScriptCancelled.
- */
-
- AppleEvent event, reply;
-
- if (!MSglobals.flscriptrunning) /*nothing to do*/
- return (true);
-
- if (!ServerSupportsFastMessages ()) {
-
- MSglobals.flscriptcancelled = true;
-
- return (true);
- }
-
- if (!IACnewverb (MSglobals.serverid, MSglobals.serverid, 'kill', &event))
- return (false);
-
- IACglobals.event = &event;
-
- if (!IACpushlongparam (MSglobals.idscript, '----'))
- return (false);
-
- if (!IACsendverbnoreply (&event, &reply))
- return (false);
-
- return (true);
- } /*CancelSharedScript*/
-
-
- pascal Boolean SharedMenuHit (idmenu, iditem) short idmenu, iditem; {
-
- /*
- returns true if the indicated menu and item indicate a shared menu item.
-
- if not, we return false -- the item is in one of your menus, you should
- process the command as you normally would.
-
- we send an IAC message to the menu server, requesting that the script
- linked into that item be run.
-
- we disable the shared menus, awaiting a 'done' message to re-enable them.
- */
-
- if (!IsSharedMenu (idmenu)) /*not a shared menu*/
- return (false);
-
- HiliteMenu (0);
-
- if (RunSharedMenuItem (idmenu, iditem)) {
-
- MSglobals.flscriptrunning = true;
-
- EnableSharedMenus (false);
- }
-
- return (true);
- } /*SharedMenuHit*/
-
-
- pascal Boolean SharedScriptCancelled (event, reply) AppleEvent *event, *reply;{
-
- /*
- call this routine in each Apple event message handler that could conceivably
- be used in a script being run by the menu server. if we return false continue
- processing the message as you normally would. if we return true, that means
- that the script that's running has been cancelled by the user; you should
- return noErr from your Apple event handler when we return true.
-
- before we return true, we reply to the message on behalf of the message
- handler. we send a specific error code of 6, this should be interpreted by
- the scripting system as "stop running the script, but don't display an
- error dialog.
-
- we admit this mechanism is somewhat klunky, but it proved too difficult to have
- Frontier be ready to respond to a "Cancel Script" Apple event while running
- the script and also giving time slices to agents.
-
- 10/21/91 DW: thanks to Kevin Calhoun (Apple) we can tell who sent the message.
- so we only reply with an error if the message arrived from the shared menu
- server. it's nice to close this loop!
- */
-
- Str255 s;
-
- if (MSglobals.flscriptcancelled && MSglobals.flscriptrunning) {
-
- IACglobals.event = event;
-
- if (IACgetsender () == MSglobals.serverid) { /*sender is shared menu server*/
-
- MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
-
- s [0] = (char) 0; /*set length to 0*/
-
- IACglobals.reply = reply;
-
- IACreturnerror (6, s); /*server watches for this special error code*/
-
- return (true);
- }
- }
-
- return (false); /*script not cancelled, keep processing message*/
- } /*SharedScriptCancelled*/
-
-
- static pascal OSErr HandleMenuDirty (event, reply, refcon) AppleEvent *event, *reply; long refcon; {
-
- /*
- this Apple event handler is called when the application's menu bar has been
- edited by the script writer in the menu server's menu editor.
-
- we just record the dirty-ness of the menus in a boolean, we'll actually re-
- load the menus when we become the foreground process.
- */
-
- #pragma unused (event, reply, refcon)
-
- MSglobals.fldirtysharedmenus = true;
-
- return (noErr);
- } /*HandleMenuDirty*/
-
-
- static pascal OSErr HandleScriptComplete (AppleEvent *event, AppleEvent *reply, long refcon) {
-
- /*
- this Apple event handler is called when a menu script has completed running.
-
- we update a couple of menu-sharing globals and re-enable the shared menus.
-
- 10/8/91 DW: added callback to support Applet Toolkit.
-
- 1/22/92 DW: set IAC globals so callback routine can pop an error string from
- the Apple Event. see appletmain.c for an example. if IACgetstringparam ('errs', s)
- returns true, there was a runtime error in the script. you can display it in an alert
- dialog. syntax errors display in an error dialog in Frontier.
- */
-
- MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
-
- EnableSharedMenus (true);
-
- IACglobals.event = event; /*1/22/92 DW*/
-
- IACglobals.reply = reply;
-
- IACglobals.refcon = refcon;
-
- if (MSglobals.scriptcompletedcallback != nil)
- (*MSglobals.scriptcompletedcallback) ();
-
- return (noErr);
- } /*HandleScriptComplete*/
-
-
- pascal Boolean InitSharedMenus () {
-
- /*
- sets the program up for menu sharing. we initialize the IAC Tools library and
- then initialize the fields of MSglobals.
-
- we install two Apple event message handlers -- one to catch the "menu needs update"
- message, and another to handle the "script has completed" message.
- */
-
- if (!IACinit ()) /*Apple events aren't present, or otherwise couldn't init*/
- return (false);
-
- MSglobals.serverid = 'LAND'; /*Frontier's creator id*/
-
- MSglobals.clientid = 0;
-
- MSglobals.hsharedmenus = nil; /*haven't loaded shared menus yet*/
-
- MSglobals.fldirtysharedmenus = true; /*force update 1st time thru event loop*/
-
- MSglobals.flscriptcancelled = false; /*script hasn't been cancelled*/
-
- MSglobals.flscriptrunning = false; /*no menu script running*/
-
- MSglobals.scriptcompletedcallback = nil;
-
- MSglobals.clientid = IACglobals.idprocess;
-
- if (!IACinstallhandler (MSglobals.clientid, 'updm', (ProcPtr) &HandleMenuDirty))
- return (false);
-
- if (!IACinstallhandler (MSglobals.clientid, 'done', (ProcPtr) &HandleScriptComplete))
- return (false);
-
- return (true);
- } /*InitSharedMenus*/
-
-
-